#include <iostream>
#include <string>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "log.hpp"
// 4个网络库
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;

class my_socket
{
public:
    my_socket(uint16_t port, string ip = "")
    :_fd(-1),
    _port(port),
    _ip(ip)
    {}
    ~my_socket(){}

    void init()
    {
        // 1. 创建socket套接字
        // 2. 填充网络信息
        // 2.1 填充基本信息 struct sockaddr_in
        // 2.2 bind 网络信息
        // AF_INET 表示网络连接（面向互联网）
        // SOCK_DGRAM 表示使用udp
        // SOCK_STREAM 表示流式传输 一般就是tcp
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_fd < 0)
        {
            logMessage(FATAL, "socket error");
            exit(1);
        }
        logMessage(DEBUG, "socket success | %d", _fd);

        // 2.1
        struct sockaddr_in local;
        bzero(&local, sizeof(local));  // 将local的每个字节设0
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);  // 转为大端
        local.sin_addr.s_addr = _ip.empty() ? htonl(INADDR_ANY) : inet_addr(_ip.c_str());

        // 2.2 bind 网络信息
        // 由于接受的是 const struct sockaddr* 所以强转
        if(bind(_fd, (const struct sockaddr*)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error");
        }
        logMessage(DEBUG, "bind success");

        // 初始化结束
    }

    // 开始网络服务
    void start()
    {
        char inBuffer[1024] = { 0 };  // 存放接受到的数据
        char outBuffer[1024] = { 0 };  // 存放发送的数据  
        while(true)
        {
            struct sockaddr_in peer;  // 输出型参数 获取发送方的数据
            socklen_t len = sizeof(peer);  // 输入输出型参数 获取接收到的数据长度
            ssize_t s = recvfrom(_fd, inBuffer, sizeof(inBuffer) - 1,
                0, (struct sockaddr*)&peer, &len);
                // s 为接受到的数据长度
            if(s < 0)
            {
                logMessage(WARNINING, "recvfrom: %s : %d", strerror(errno), _fd);
                continue;  // 服务器不退出
            }

            // 读取成功的,除了读取到对方的数据，你还要读取到对方的网络地址[ip:port]
            std::string peerIp = inet_ntoa(peer.sin_addr);       //拿到了对方的IP
            uint32_t peerPort = ntohs(peer.sin_port); // 拿到了对方的port

            // checkOnlineUser(peerIp, peerPort, peer); //如果存在，什么都不做，如果不存在，就添加

            // 打印出来客户端给服务器发送过来的消息
            logMessage(NOTICE, "[%s:%d]# %s", peerIp.c_str(), peerPort, inBuffer);
            bzero(inBuffer, sizeof(inBuffer));
        }
    }

private:
    int _fd;
    uint16_t _port;
    string _ip;
};


int main()
{
    my_socket udpServe(8553);
    udpServe.init();
    udpServe.start();
    return 0;
}